package br.cesed.lti.ementol.dao;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import br.cesed.lti.ementol.dao.util.HibernateFactory;

import cc.co.taciano.webbase.Fachada;
import cc.co.taciano.webbase.bean.Bean;
import cc.co.taciano.webbase.dao.DAOException;

/**
 * Classe abstrata topo da hierarquia de DAO's (Data Access Object).
 * @author Taciano Morais Silva
 * @version 12/02/2009, 11h28m
 * @since 15/10/2008, 12h00m
 */
public abstract class AbstractDao<T extends Bean> {

    protected Session session;
    protected Transaction tx;
    private Fachada fachada;
    private String banco;

    public static final String CSW = "csw";

    /**
     * @throws DataAccessLayerException
     */
    public AbstractDao() throws DAOException {
        HibernateFactory.buildIfNeeded();
    }

    /**
     * @throws DAOException
     */
    public AbstractDao(String banco) throws DAOException {
        this.banco = banco;
        HibernateFactory.buildIfNeeded(banco);
    }

    /**
     * @param fachada
     * @throws DAOException
     */
    public AbstractDao(Fachada fachada) throws DAOException {
        this();
        this.fachada = fachada;
    }

    /**
     * @param fachada
     * @throws DAOException
     */
    public AbstractDao(Fachada fachada, String banco) throws DAOException {
        this(banco);
        this.fachada = fachada;
    }

    /**
     * @param obj
     * @throws DAOException
     */
    protected void saveOrUpdate(T obj) throws DAOException {
        try {
            startOperation();
            session.saveOrUpdate(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
    }

    /**
     * @param obj
     * @throws DAOException
     */
    protected void delete(T obj) throws DAOException {
        try {
            startOperation();
            session.delete(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
    }

    /**
     * @param clazz
     * @param id
     * @throws DAOException
     */
    protected void delete(Class<T> clazz, Integer id) throws DAOException {
        Object obj = null;
        try {
            startOperation();
            obj = session.load(clazz, id);
            session.delete(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
    }

    /**
     * @param clazz
     * @param id
     * @return
     * @throws DAOException
     */
    protected Object find(Class<T> clazz, Integer id) throws DAOException {
        Object obj = null;
        try {
            startOperation();
            obj = session.load(clazz, id);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            //HibernateFactory.close(session);
            //if (fachada != null) {
                fachada.addSessaoHibernate(session);
            //}
        }
        return obj;
    }

    /**
     * @param clazz
     * @return
     * @throws DAOException
     */
    @SuppressWarnings("unchecked")
    protected List<T> findAll(Class<T> clazz) throws DAOException {
        List<T> objects = null;
        try {
            startOperation();
            Query query = session.createQuery("from " + clazz.getName());
            objects = query.list();
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return objects;
    }

    /**
     * @throws HibernateException
     */
    protected void startOperation() throws HibernateException {
        session = HibernateFactory.openSession(banco);
        tx = session.beginTransaction();
    }

    /**
     * @param e
     * @throws DAOException
     */
    protected void handleException(HibernateException e) throws DAOException {
        HibernateFactory.rollback(tx);
        throw new DAOException(e);
    }
}
